use std::ops::Deref;

/// # 常用场景
/// - 在编译时，某类型的大小无法确定。但使用该类型时，上下文却需要知道它的确切大小
/// - 当你有大量数据，想移交所有权，但需要确保在操作时数据不会被复制
/// - 使用某个值时，你只关心它是否实现了特定的trait，而不关心他的具体类型
/// -----------
/// # Deref Trait  解引用
/// - 实现Deref Trait使我们可以自定义解引用运算符*的行为
/// - 通过实现Deref，智能指针可像常规引用一样来处理数据
/// # 解引用与可变性
/// 下面三种情况下，Rust会执行deref coercion
/// - 当T:Deref<Target=U>,允许&mT转换为&U
/// - 当T:DerefMut<Target=U>,允许&mut T转换为&mut U
/// - 当T:DerefM<Target=U>,允许&mut T转换为& U，但是不能将&T转换为&mut U(这种转换需要该引用时唯一的，但是这个不能保证)
/// # Drop Trait
/// 释放就是栈的释放  先进后出
/// 需要手动释放需要使用std::mem::drop(Value)
/// 编译器能控制的就是栈的释放。堆的释放是手动的，但是往往会和栈的联动。
/// # Rc<T>  引用计数智能指针
/// 一个值会有多个所有者，-多个引用
/// 没有引用时，可以清除该数据
/// 使用场景
/// 需要在heap（堆）上分配数据，这些数据被程序的多个部分读取（只读），但在编译时无法确定那个部分最后使用完这些数据
/// 只能用于单线程场景
/// 用法
/// 不在预导入模块中
/// Rc::clone(&a) 增加引用计数
/// Rc::strong_count(&a) 获得引用计数
/// 
use crate::List::{Cons, Nil};

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(t: T) -> MyBox<T> {
        MyBox(t)
    }
}

impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0 // &(self.0)
    }
}

fn hello(name: &str) {
    println!("Hello, {}", name);
}

// drop trait的实例

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data : {}",self.data);
    }
}

fn main() {
    let name = MyBox::new(String::from("ZXX"));
    // &name &MyBox<String>
    // deref &String
    // deref &str
    // rust 对于使用的变量，如果不满足需要的类型。会试着一直加 *
    hello(&name);
    hello(&(*name)[..]);

    // let b = Box::new(5);
    // println!("b = {}",b);
    // let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3,Box::new(Nil))))));

    let b  = CustomSmartPointer {data:String::from("My stuff")};
    let c  = CustomSmartPointer {data:String::from("Other stuff")};
    println!("CustomSmartPointer created.");
}

enum List {
    Cons(i32, Box<List>),
    Nil,
}
